package eerbaar.collision.internal;

import eerbaar.collision.ICollisionCallback;
import eerbaar.commons.Color;
import eerbaar.elements.IElement;
import eerbaar.elements.extension.IFoodElement;
import eerbaar.elements.extension.INonMovingElement;
import eerbaar.elements.extension.IPointConsumer;
import eerbaar.elements.extension.IPointSource;
import eerbaar.elements.extension.IPoints;
import eerbaar.message.lib.CollisionMsg;
import eerbaar.message.lib.DisplayRisingTextMsg;
import eerbaar.message.lib.MsgFactory;
import eerbaar.message.lib.NotifyEatMsg;
import eerbaar.message.lib.NotifyEatPackBoneMsg;
import eerbaar.message.lib.ScoreChangeMsg;
import eerbaar.position.IPosition;
import eerbaar.shared.message.MsgHelper;

class CollisionProcessor {

    protected IElement consumer;
    protected IElement source;
    protected IElement nonMoving;

    protected boolean canSendRisingText() {

        if (this.nonMoving != null) {

            IPointSource s = this.nonMoving.getExtension(IPointSource.class);
            if (s != null) {

                return false;
            }

            return true;
        }

        return false;
    }

    protected boolean canTransferPoints() {

        if (this.consumer != null && this.source != null) {

            return true;
        }

        return false;
    }

    protected void handleNonMover(ICollisionCallback callback) {

        if (this.consumer == null || this.nonMoving == null) {

            return;
        }

        String description = this.nonMoving.getName();
        CollisionMsg msg = MsgFactory.createCollisionMsg(description);
        MsgHelper.sendMsg(CollisionMsg.class, msg);
    }

    protected boolean isNonMoverHit() {

        if (this.consumer != null && this.nonMoving != null) {

            if (this.consumer.getName().equals("pet")) {

                return true;
            }
        }

        return false;
    }

    void process(IElement e1, IElement e2, ICollisionCallback callback) {

        if (e1 == e2) {
            return;
        }

        setup(e1, e2);

        if (canTransferPoints()) {

            transferPoints(callback);
        } else if (isNonMoverHit()) {

            handleNonMover(callback);
        } else if (canSendRisingText()) {

            sendRisingText();
        }
    }

    protected void sendCollissionMsg() {

        if (!this.consumer.getName().equals("pet")) {
            return;
        }

        String description = "";
        if (this.source.getName().equals("pet")) {
            description = this.consumer.getName();
        } else {
            description = this.source.getName();
        }

        CollisionMsg msg = MsgFactory.createCollisionMsg(description);
        MsgHelper.sendMsg(CollisionMsg.class, msg);
    }

    protected void sendMessages(final int points) {

        if (this.source == null) {
            return;
        }

        sendCollissionMsg();
        MsgHelper.sendMsg(ScoreChangeMsg.class, new ScoreChangeMsg());

        IPosition p = this.source.getPosition();
        if (points > 0) {

            if (this.consumer.getName().equals("pet")) {

                MsgHelper.sendMsg(
                        DisplayRisingTextMsg.class,
                        new DisplayRisingTextMsg("+" + points, p.getX(), p
                                .getY()));

            }

            if (this.source.getExtension(IFoodElement.class) != null) {

                if (this.source.getName().endsWith("bone")) {
                    NotifyEatMsg msg = new NotifyEatMsg();
                    msg.put("source.name", this.source.getName());
                    MsgHelper.sendMsg(NotifyEatMsg.class, msg);
                } else {
                    NotifyEatPackBoneMsg msg = new NotifyEatPackBoneMsg();
                    msg.put("source.name", this.source.getName());
                    MsgHelper.sendMsg(NotifyEatPackBoneMsg.class, msg);
                }
            }

        } else if (points < 0) {

            MsgHelper.sendMsg(DisplayRisingTextMsg.class,
                    new DisplayRisingTextMsg("" + points, p.getX(), p.getY(),
                            Color.RED));
        }
    }

    protected void sendRisingText() {

        if (this.nonMoving == null) {
            return;
        }

        IElement e = this.nonMoving.getExtension(IElement.class);
        String sourceName = e.getName();

        IPosition p = e.getPosition();
        MsgHelper.sendMsg(DisplayRisingTextMsg.class, new DisplayRisingTextMsg(
                "" + sourceName, p.getX(), p.getY()));
    }

    protected void setup(IElement e1, IElement e2) {

        IElement[] elements = new IElement[] { e1, e2 };

        for (IElement e : elements) {

            IPointConsumer c = e.getExtension(IPointConsumer.class);

            if (c == null) {

                continue;
            }

            if (this.consumer == null) {

                this.consumer = e;
            } else {

                if (c.getPriority() == IPointConsumer.Priority.HIGH) {

                    this.consumer = e;
                }
            }
        }

        for (IElement e : elements) {

            IPointSource s = e.getExtension(IPointSource.class);

            if (s == null) {
                continue;
            }

            IPoints points = s.getExtension(IPoints.class);
            if (points.getPoints() == 0) {
                continue;
            }

            if (this.source == null && e != this.consumer) {

                this.source = e;
            }
        }

        for (IElement e : elements) {

            INonMovingElement s = e.getExtension(INonMovingElement.class);

            if (s == null) {
                continue;
            }

            if (this.nonMoving == null && e != this.consumer) {

                this.nonMoving = e;
            }
        }
    }

    protected void transferPoints(ICollisionCallback callback) {

        if (this.consumer == null || this.source == null) {

            return;
        }

        IPoints to = this.consumer.getExtension(IPoints.class);
        IPoints from = this.source.getExtension(IPoints.class);

        if (to != null && from != null) {

            IPointConsumer c = this.consumer.getExtension(IPointConsumer.class);
            int max = c.getPointsToTake();

            final int points = from.getPoints();
            int take = points;
            if (take > max) {
                take = max;
            }

            to.setPoints(to.getPoints() + take);
            from.setPoints(points - take);

            IFoodElement food = this.source.getExtension(IFoodElement.class);
            if (food != null) {
                callback.removeElement(this.source);
            }

            int display = take;
            if (this.source.getName().equals("pet")) {
                display = -display;
            }

            sendMessages(display);
        }
    }

}
